// import * as dhx from "../../3thComponents/diagram/codebase/diagramWithEditor.js";
import "../../3thComponents/diagram/codebase/diagramWithEditor.css";
import _ from "lodash";
export default class StarDiagram {
  constructor(el, config = {}) {
    this.el = el;
    this.config = _.merge(this.configTpl(), config);
    this.data = [];
    this.diagramData = [];
    this.templates = [];
  }
  setDiagram() {
    this.config.options.shapeToolbar = this.setToolbar(this.config.shapeToolbar)
    this.diagram = new dhx.Diagram(this.el, this.config.options);
    this.addTempalte(this.config.templates);
    this.addShapes(this.templates)
  }
  setDiagramEditor() {
    this.config.options.shapeToolbar = this.setToolbar(this.config.shapeToolbar)
    this.editor = new dhx.DiagramEditor(this.el, this.config.options);
    this.diagram = this.editor.diagram;
    this.addTempalte(this.config.templates);
    this.addShapes(this.templates)
  }
  static create(el, config) {
    let diagram = new StarDiagram(el, config);
    diagram.setDiagram();
    return diagram;
  }
  static createEditor(el, config) {
    let diagram = new StarDiagram(el, config);
    diagram.setDiagramEditor();
    return diagram;
  }
  /**配置模板和配置方法****************************** */
  /**
   * 缺省配置模板
   * @returns 
   */
  configTpl(){
    return {
        editor:true,
        dataMapping:{},
        shapeToolbar:{},
        templates:[],
        options:this.optionsTpl()
    }
  }
  /**
   * 缺省配置的选项部分
   * @returns 
   */
  optionsTpl() {
    return {
      width: "100%",
      height: "100%",
      type: "default", //"default" | "org" | "mindmap"模式中的一种（缺省|组织结构|脑图）
      select: false, //鼠标框选是否有效
      lineConfig: {
        //连接线配置
        lineType: "line", //"dash" | "line"，虚线|实线
      },
      gridStep: 10, //网格间距
      /**以下default模式有效*/
      autoplacement: {
        //图元连接方式配置
        mode: "edges", //"direct" | "edges"，edges为在图元边连接点处连接
        graphPadding: 100, //图元间距，缺省为200
      },
      lineGap: 50, //连接线与图元的间距
      editMode: false, //配置是否显示左右面板（左为图例，右为属性）
      shapeToolbar: [
        //配置选中图元时，图元顶部的工具栏
      ],
      /**以下default模式有效*/
      shapeSections: {
        //配置图例内容
        // "Flowchart shapes": [{ flowShapes: true }],
        // process:[
        //   'processStart'
        // ]
      },
    };
  }
  /**
   * 缺省的节点模板
   * @param {模板配置} cfg 
   * @returns 
   */
  templateTpl(cfg) {
    let config = _.merge(
      {
        category:'pic',
        type: "general",
        width: 180,
        height: 160,
        img:'',
        alt:'',
        style: '',
        typeStyle:'',
        headStyle:'',
        imageStyle: '',
        titleStyle: '',
        textStyle: '',
        header:'',
        title: "abc",
        text: "vvv",
        mark: "a",
        params: {
          a: "abc",
        },
      },
      cfg
    );
    if(cfg.category=="pic"){
      return {
        defaults: {
          ...config,
          width: 180,
          height: 160,
        },
        template: function (shape) {
          return `
            <section class="star_diagram_template_pic" style="${shape.style}">
              <img class="img" style="${shape.imageStyle}" src="${shape.img}" alt="${shape.alt}"></img>
              <span class="title" style="${shape.titleStyle}">${_.get(shape.params,shape.title,shape.title)}</span>
              <span class="text" style="${shape.textStyle}">${_.get(shape.params,shape.text,shape.text)}</span>
            </section>`;
        },
      };
    }else if(cfg.category=="pic2"){
      return {
        defaults: {
          ...config,
          width: 200,
          height: 100,
        },
        template: function (shape) {
          return `
            <section class="star_diagram_template_pic2" style="${shape.style}">
              <img class="img" style="${shape.imageStyle}" src="${shape.img}" alt="${shape.alt}"></img>
              <section class="body">
                <span class="title" style="${shape.titleStyle}">${_.get(shape.params,shape.title,shape.title)}</span>
                <span class="text" style="${shape.textStyle}">${_.get(shape.params,shape.text,shape.text)}</span>
              </section>
            </section>`;
        },
      };
    }else{
      return {
        defaults: {
          ...config,
          width: 180,
          height: 100,
        },
        template: function (shape) {
          return `
            <section class="star_diagram_template_model" style="${shape.style}">
              <section class="type" style="${shape.typeStyle}">${_.get(shape.params,shape.type,shape.type)}</section>
              <section class="body">
                <span class="title" style="${shape.titleStyle}">${_.get(shape.params,shape.title,shape.title)}</span>
                <span class="text" style="${shape.textStyle}">${_.get(shape.params,shape.text,shape.text)}</span>
              </section>
            </section>
        `;
        },
      };
  }
  }
  /**
   * 节点上的工具条菜单模板
   * @param {菜单图标名称} name 
   * @returns 
   */
  toolbarTpl(name){
    return {
        copy:{
            id: "copy",
            content:
                '<i class="ivu-icon ivu-icon-md-copy" style="font-size: 20px"</i>',
            tooltip: "Copy"
        },
        remove:{
            id: "remove",
            content:
              '<i class="ivu-icon ivu-icon-md-trash" style="font-size: 20px"</i>',
            tooltip: "Remove"
        },
        download:{
            id: "download",
            content: "<i class='dxi dxi-download'></i>",
          	tooltip: "Download"
        },
        info:{
            id: "info",
            content: "<i class='dxi dxi-information-outline'></i>",
          	tooltip: "Info"
        }
    }[name]
  }
  /**
   * 按照工具条配置获取工具条
   * @param {工具条配置} toolbars 
   * @returns 
   */
  setToolbar(toolbars){
    return Object.keys(toolbars).map(name=>{
        let toolbar = this.toolbarTpl(name);
        if(toolbar){
            toolbar.check = toolbars[name];
            return toolbar
        }
    })
  }
  /**
   * 按照图元配置获取图元
   * @param {图元配置} templates 
   */
  addTempalte(templates) {
    this.templates = templates.map((template) => {
      return this.templateTpl(template);
    });
  }
  addShapes(shapes) {
    shapes.map((shape) => {
      this.diagram.addShape(shape.defaults.type, shape);
    });
  }
  /**初始化工具栏、左右面板*/
  setEditorPanel(cfg) {
    if (!cfg) {
      cfg = { toolbar: false, leftPanel: false, rightPanel: false };
    }
    let { toolbar, leftPanel, rightPanel } = cfg;
    if (!toolbar) {
      let toolbarDom = document.querySelector(".dhx_topbar");
      if (toolbarDom) {
        toolbarDom.style.display = "none";
      }
    }
    if (!leftPanel) {
      let leftPanelDom = document.querySelector(
        ".dhx_diagram_editor_shapebar__container"
      );
      if (leftPanelDom) {
        leftPanelDom.style.display = "none";
      }
    }
    if (!rightPanel) {
      let rightPanelDom = document.querySelector(
        ".dhx_diagram_editor__sidebar"
      );
      if (rightPanelDom) {
        rightPanelDom.style.display = "none";
      }
    }
  }
  /**数据装配方法****************************** */
  setData(data,mapping = this.config.mapping){
    this.data = data;
    this.setDiagramData(this.factoryData(data,mapping));
  }
  factoryData(data,mapping){
    let diagramData = [];
    data.map(row=>{
        let shape = {
            id:mapping.id,
            type:mapping.type,
            title:mapping.title,
            text:mapping.text,
            mark:mapping.mark,
            params:row
        };
        diagramData.push(shape);
    })
    data.map(row=>{
        if(row[mapping.from]&&row[mapping.to]){
            let line = {
                type:'line',
                from:_.get(row,mapping.from),
                to:_.get(row,mapping.to),
                forwardArrow: "filled"
            }
            diagramData.push(line);
        }
    })
    return diagramData;
  }
  
  setDiagramData(diagramData) {
    this.diagramData = diagramData;
    this.diagram.data.parse(diagramData);
  }
  getDiagramData() {
    this.diagramData = this.diagram.data.serialize();
    return this.diagramData;
  }
  getLines() {
    return this.diagramData.filter((item) => {
        if(item.type === "line" || !item.type){
            return item;
        }
    });
  }
  getNodes() {
    return this.diagramData.filter((item) => {
        if(item.type !== "line" && item.type){
            return item;
        }
    });
  }
  formatLines() {
    let lines =  this.getLines();
    lines = lines.filter(line=>{
        if(line.from&&line.to){
            return line;
        }
    });
    let uniqueList = lines.reduce((acc, curr) => {
        let hasDuplicate = acc.find((obj) => obj.from === curr.from && obj.to === curr.to);
      if (!hasDuplicate) {
        acc.push(curr);
      }
      return acc;
    }, []);
    return uniqueList; //返回去重后的数组
  }
  formatData(){
    let lines = this.formatLines();
    let nodes = this.getNodes();
    this.setDiagramData([...nodes,...lines])
  }
  extractData(){
    this.getDiagramData();
    this.data = this.diagramData.map(item=>{
        if(!!item.type&&item.type!='line'&&item.params){
            return item.params;
        }
    });
    return this.data;
  }

  autoPlace(cfg = {}) {
    this.diagram.autoPlace({
      mode: "edges",
      placeMode: "radial",
      ...cfg,
    });
  }
  paint() {
    this.diagram.paint();
  }
  exportPdf(){
    this.diagram.export.pdf();
  }
  /**设置事件方法*/
  setEditorEvent(name,fn) {
    if(name==='beforeShapeIconClick'){
        this.editor.events.on('beforeShapeIconClick',async (iconId,shape)=>{
            fn(iconId,shape)
        })
    }
    if(name==='afterShapeIconClick'){
        this.editor.events.on('afterShapeIconClick',async (iconId,shape)=>{
            this.getDiagramData();
            fn(iconId,shape)
        })
    }
  }
  setDiagramEvent(name, fn){
    if(name==='shapeClick'){
        this.diagram.events.on("shapeClick", (id, event) => {
            fn(id, event)
        })
    }
    if(name==='shapeDblClick'){
        this.diagram.events.on("shapeDblClick", (id, event) => {
            fn(id, event)
        })
    }
    if(name==='lineClick'){
        this.diagram.events.on("lineClick", (id, event) => {
            fn(id, event)
        })
    }
    if(name==='lineDblClick'){
        this.diagram.events.on("lineDblClick", (id, event) => {
            fn(id, event)
        })
    }
    if(name==='afterAdd'){
        this.diagram.events.on("afterAdd", (newItem) => {
            if(!!newItem.type&&newItem.type==='line') newItem.forwardArrow = 'filled';
            this.getDiagramData();
            fn(newItem)
        })
    }
    if(name==='afterRemove'){
        this.diagram.events.on("afterRemove", (newItem) => {
            this.getDiagramData();
            fn(newItem)
        })
    }
    if(name==='beforeAdd'){
        this.diagram.events.on("beforeAdd", (newItem) => {
            fn(newItem)
        })
    }
    if(name==='beforeRemove'){
        this.diagram.events.on("beforeRemove", (newItem) => {
            fn(newItem)
        })
    }
    if(name==='change'){
        this.diagram.events.on("change", (id, status, shape) => {
            this.getDiagramData();
            fn(id, status, shape)
        })
    }
    if(name==='load'){
        this.diagram.events.on("load", () => {
            fn()
        })
    }
  }
  shapeTpl(){
    return {
        // type?: string,
        // id?: string | number,
        // x?: number, // required in the default mode of Diagram
        // y?: number, // required in the default mode of Diagram
        // text?: string | string[],
        // editable?: boolean, // true by default
        // height?: number,
        // width?: number,
        // fixed?: boolean, // false by default
        // hidden?: boolean
    }
  }
  lineTpl(){
    return {
        // type?: "line" | "dash", // "line" by default
        // id?: string | number,
        // from?: string | number,
        // to?: string | number,
        // connectType?: "straight" | "elbow" | "curved",
        // strokeWidth?: number, // 2 by default
        // stroke?: string
    }
  }
}
